<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>1_类的基本知识</title>
</head>
<body>
  <script type="text/javascript">
  /* 
    总结:
      1.类中的构造器不是必须写的，要对实例进行一些初始化的操作，如添加指定属性时才写。
      2.如果A类继承了B类，且A类中写了构造器，那么A类构造器中的super是必须要调用的。
      3.类中所定义的方法,都是放在了类的原型对象上，供实例去使用
  */

  // 创建一个Person类
  class Person {
    // 构造器方法
    constructor(name, age) {
      // 构造器中的this是谁？————类的实例对象
      this.name = name
      this.age = age
    }
    // 一般方法
    speak() {
      // speak方法放在了哪里？————类的原型对象上，供实例使用
      // 通过Person实例调用speak时，speak中的this就是Person实例
      console.log(`我叫${this.name}，我的年龄是${this.age}`)
    }
  }
  // 创建一个Person的实例对象
  var p1 = new Person("Tom", 30)
  var p2 = new Person("LiLei", 32)

  console.log(p1)
  console.log(p2)

  p1.speak()
  p2.speak()
  // p1.speak.call({a:1, b:2})    call apply bind可以改变this指向

  // 创建一个Student类，继承于Person类
  class Student extends Person {
    constructor(name, age, grade) {
      super(name, age)      // 必须写在最前面，并且写入参数
      this.grade = grade
    }
    // 重写从父类继承过来的方法
    speak() {
      console.log(`我叫${this.name}，我的年龄是${this.age}，我读的是${this.grade}年级`)
      // study()  报错，不能直接调用
      this.study()
    }
    study() {
      // study方法放在了哪里？————类的原型对象上，供实例使用
      // 通过Student实例调用study时，study中的this就是Student实例
      console.log("我很努力的学习")
    }
  }

  var s1 = new Student("小张", 15, "高一")

  console.log(s1)
  s1.speak()
  s1.study()

  class Car {
    constructor(name, price) {
      this.name = name
      this.price = price
      // this.wheel = 4
    }

    // 实例对象上添加属性
    a = 1
    wheel = 4

    // 类的原型上添加属性
    static num = 100
  }

  const c1 = new Car('奔驰c63', 199)
  const c2 = new Car('宝马', 299)
  console.log(c1)
  console.log(c2)
    
  </script>
</body>
</html>